package com.vmock.biz.tcp;

import com.vmock.biz.entity.Log;
import com.vmock.biz.entity.Response;
import com.vmock.biz.entity.Url;
import com.vmock.biz.service.ILogService;
import com.vmock.biz.service.IResponseService;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;

//@Component
//@Scope("prototype")
@Getter
@Setter
@Slf4j
public class TcpConn {


    private static Integer port;
    private TcpServerStatusEnum status;
    private ServerSocket serverSocket ;
    private Thread masterThread ;
    private Response response;
    private  Url item;
    private  IResponseService responseService;
    private ILogService logService;
//    private Executors
    public TcpConn(Url item, IResponseService responseService, ILogService logService) {
        this.responseService = responseService;
        this.item = item;
        this.logService = logService;
        try {
            serverSocket = new ServerSocket(item.getPort());
            status = TcpServerStatusEnum.RUNING;
        } catch (IOException e) {
            log.info(item.getPort() +" 启动失败: "+e.getMessage());
            return;
        }
        this.masterThread = new Thread(new TcpMaster(serverSocket,item,logService),"boss-thread-"+(item.getPort()));
        this.masterThread.start();
        log.info(item.getPort()+" 服务启动 success thread = "+masterThread.getName());
    }

    private static class WorkThread implements ThreadFactory{
        private int workThreadNum;
        public WorkThread(int workThreadNum){
            this.workThreadNum = workThreadNum;
        }
        @Override
        public Thread newThread(Runnable r) {
            return new Thread(r,Thread.currentThread().getName()+"-work-thread-"+(++workThreadNum));
        }

    }
    private class TcpMaster implements Runnable {
        ServerSocket serverSocket;
        private final ILogService logService;
        Url item;
        public TcpMaster(ServerSocket serverSocket, Url item,ILogService logService) {
            this.serverSocket = serverSocket;
            this.item = item;
            this.logService = logService;
        }

        @Override
        public void run() {
            int workThreadNum = 0;
            ExecutorService executorService = Executors.newFixedThreadPool(20, new WorkThread(workThreadNum));
            Response response = responseService.selectMainResponse(item.getUrlId());
            while (TcpServerStatusEnum.RUNING.equals(status)) {
                try {
                    Socket client = serverSocket.accept();
                    executorService.submit(new tcpWorker(client, response, logService));
                } catch (SocketException e1) {
                    log.warn(serverSocket.getLocalPort() + " 服务关闭: {}", e1.getMessage());
                } catch (IOException e) {
                    log.error(serverSocket.getLocalPort() + " 服务关闭异常: {}", e.getMessage());
                    throw new RuntimeException(e);
                }
            }
            executorService.shutdown();
            log.info(item.getPort()+" master线程池 服务停止："+status.getStatus());
        }
    }


    private static class tcpWorker implements Runnable {

        private final Socket client;
        private final Response response ;
        private final ILogService logService;
        public tcpWorker(Socket client, Response response, ILogService logService) {
            this.client = client;
            this.response = response;
            this.logService =  logService;
        }

        @Override
        public void run() {
            log.info("客户端地址：{}",client.getRemoteSocketAddress().toString());
            OutputStream outputStream = null;
            InputStream inputStream = null;
            ByteArrayOutputStream outByte = null;
            String req;
            try {
                byte [] buff = new byte[1024];
                int len;
                inputStream = client.getInputStream();
                outByte = new ByteArrayOutputStream();
                while ( ( len = inputStream.read(buff)) > 0 ){
                    outByte.write(buff,0,len);
                    if (len < buff.length) {
                        break;
                    }
                }
                req = outByte.toString();
                log.info("收到报文：[ {} ]",req);
                outputStream = client.getOutputStream();
                if (response == null || outByte.toString().contains("/favicon.ico")) {
                    String resp = "{\"hi\":\"hello world\"}";
                    log.info("返回报文：[ {} ]",resp);
                    recodeLog(logService,req,resp);
                    outputStream.write(resp.getBytes());
                }else {
                    byte[] resBytes = response.getContent().getBytes();
                    String headlens = StringUtils.leftPad(String.valueOf(resBytes.length), 10, "0");
                    log.info("headlen =[ {} ]",headlens);
//                    String resp = headlens + response.getContent();
                    String resp = response.getContent();
                    log.info("返回报文：[ {} ]",resp);
                    recodeLog(logService,req,resp);
                    outputStream.write(resp.getBytes());
                }
                outputStream.flush();
                client.shutdownInput();
                client.shutdownOutput();
                client.close();
            } catch (IOException e) {
                log.warn("outputStream closed",e);
                throw new RuntimeException(e);
            }finally {
                try {
                    if (inputStream != null) {
                        inputStream.close();
                    }
                    if (outputStream != null) {
                        outputStream.close();
                    }
                    if (outByte != null) {
                        outByte.close();
                    }
                } catch (IOException e) {
                    log.error("关闭流错误！",e);
                }
            }
        }

        private void recodeLog(ILogService logService, String req, String resp) {
            Log mockLog = new Log();
            // 命中url，系统中配置的，可能是带path占位符的
            mockLog.setHitUrl(String.valueOf(port));
            // 实际url
            mockLog.setRequestUrl(client.getRemoteSocketAddress().toString());
            // ip
            mockLog.setRequestIp(client.getRemoteSocketAddress().toString());
            // request method
            mockLog.setRequestMethod("Socket");
            // request detail
            mockLog.setRequestDetail(req);
            // 日志处理，只有成功命中的场合才记录详细，防止产生过多垃圾数据。
//            JSONObject responseDetailJson = new JSONObject();
//            // 响应http码
//            responseDetailJson.put("respStatus", "200");
//            // header
////            String customHeader = mockResponse.getCustomHeader();
////            if (StrUtil.isNotBlank(customHeader)) {
////                responseDetailJson.put("respHeader", new JSONArray(customHeader));
////            }
//            // 相应内容
//            responseDetailJson.put("respContent", resp);
            // response detail
            mockLog.setResponseDetail(resp);
            // 异步插入
            logService.asyncInsert(mockLog);
        }
    }
}
